<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>第16章 关于 Vue 3.0 | 深入理解Vue.js实战</title>
    <meta name="generator" content="VuePress 1.9.7">
    
    <meta name="description" content="作者：被删">
    
    <link rel="preload" href="/vue-ebook/assets/css/0.styles.2728a2da.css" as="style"><link rel="preload" href="/vue-ebook/assets/js/app.a856ee15.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/2.2a4d101b.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/3.9083e877.js" as="script"><link rel="preload" href="/vue-ebook/assets/js/15.e8ce977a.js" as="script">
    <link rel="stylesheet" href="/vue-ebook/assets/css/0.styles.2728a2da.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/vue-ebook/" class="home-link router-link-active"><!----> <span class="site-name">深入理解Vue.js实战</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/vue-ebook/" class="nav-link">概述</a></div><div class="nav-item"><a href="/vue-ebook/vue-ebook/" class="nav-link router-link-active">内容</a></div> <a href="https://github.com/godbasin/vue-ebook" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/vue-ebook/" class="nav-link">概述</a></div><div class="nav-item"><a href="/vue-ebook/vue-ebook/" class="nav-link router-link-active">内容</a></div> <a href="https://github.com/godbasin/vue-ebook" target="_blank" rel="noopener noreferrer" class="repo-link">
    Github
    <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></nav>  <ul class="sidebar-links"><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>前言</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/0.html" class="sidebar-link">前端框架的出现</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>第一部分 Vue快速入门</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/1.html" class="sidebar-link">第1章 Vue 框架介绍</a></li><li><a href="/vue-ebook/vue-ebook/2.html" class="sidebar-link">第2章 Vue 环境快速搭建</a></li><li><a href="/vue-ebook/vue-ebook/3.html" class="sidebar-link">第3章 Vue 基础介绍</a></li><li><a href="/vue-ebook/vue-ebook/4.html" class="sidebar-link">第4章 Vue 组件的使用</a></li><li><a href="/vue-ebook/vue-ebook/5.html" class="sidebar-link">第5章 常用指令和自定义指令</a></li><li><a href="/vue-ebook/vue-ebook/6.html" class="sidebar-link">第6章 Vue 动画</a></li><li><a href="/vue-ebook/vue-ebook/7.html" class="sidebar-link">第7章 Vue Router 路由搭建应用</a></li><li><a href="/vue-ebook/vue-ebook/8.html" class="sidebar-link">第8章 实战：Todo List 从组件到应用</a></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:10px;"><div class="kitty-main" data-v-2b653b36><span class="stand" data-v-2b653b36></span> <div class="cat" data-v-2b653b36><div class="body" data-v-2b653b36></div> <div class="head" data-v-2b653b36><div class="ear" data-v-2b653b36></div> <div class="ear" data-v-2b653b36></div></div> <div class="face" data-v-2b653b36><div class="nose" data-v-2b653b36></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div> <div class="whisker-container" data-v-2b653b36><div class="whisker" data-v-2b653b36></div> <div class="whisker" data-v-2b653b36></div></div></div> <div class="tail-container" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36><div class="tail" data-v-2b653b36></div></div></div></div></div></div></div></div></div></div> <p class="sidebar-heading open"><span>第二部分 Vue的正确使用方式</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/9.html" class="sidebar-link">第9章 思维转变与大型项目管理</a></li><li><a href="/vue-ebook/vue-ebook/10.html" class="sidebar-link">第10章 如何正确地进行抽象</a></li><li><a href="/vue-ebook/vue-ebook/11.html" class="sidebar-link">第11章 全局数据管理与 Vuex</a></li><li><a href="/vue-ebook/vue-ebook/12.html" class="sidebar-link">第12章 实战：三天开发一个管理端</a></li><li><a href="/vue-ebook/vue-ebook/13.html" class="sidebar-link">第13章 实战：表单配置化实现</a></li><li><a href="/vue-ebook/vue-ebook/14.html" class="sidebar-link">第14章 实战：使用 Webpack 或 Vue CLI 搭建多页应用</a></li><li><a href="/vue-ebook/vue-ebook/15.html" class="sidebar-link">第15章 Vue 周边拓展</a></li><li><a href="/vue-ebook/vue-ebook/16.html" aria-current="page" class="active sidebar-link">第16章 关于 Vue 3.0</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/16.html#_16-1-vue-3-0-兼容性" class="sidebar-link">16.1 Vue 3.0 兼容性</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/16.html#_16-2-设计目标" class="sidebar-link">16.2 设计目标</a></li><li class="sidebar-sub-header"><a href="/vue-ebook/vue-ebook/16.html#_16-3-vue-3-0-pre-alpha" class="sidebar-link">16.3 Vue 3.0 Pre Alpha</a></li></ul></li></ul></section></li><li><section class="sidebar-group depth-0" style="padding-top:;"><!----> <p class="sidebar-heading"><span>后记</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/vue-ebook/vue-ebook/99.html" class="sidebar-link">关于框架选型</a></li></ul></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="第16章-关于-vue-3-0"><a href="#第16章-关于-vue-3-0" class="header-anchor">#</a> 第16章 关于 Vue 3.0</h1> <p>Vue 3.0 目前已经公开源代码了，感兴趣的小伙伴可以去https://github.com/vuejs/vue-next查看。关于Vue 3.0 相信大家都好奇很久了，之前的 RFC 讨论也是相当激烈。而这一版本在设计上的一些理念，这里会给大家介绍一下，大家可以在前面内容的基础上来进行渐进式学习，这与 Vue 框架的“渐进式框架”定位也比较相符。</p> <h2 id="_16-1-vue-3-0-兼容性"><a href="#_16-1-vue-3-0-兼容性" class="header-anchor">#</a> 16.1 Vue 3.0 兼容性</h2> <p>对于大多数开发者来说，尤其是经历过 Angular 断崖式升级的小伙伴们，对框架升级最担心的是兼容性。新能力大家当然想用，但对于项目和业务来说，稳定性是首位的，所以很多人会担心框架升级是否部分功能不可用。Vue 3.0 有不少新的想法和改动，但基本上兼容性大部分是没问题的。总体来看，除渲染函数 API 和<code>scoped-slot</code>语法之外，其余均保持不变或者将通过另外构建一个兼容包来兼容 2.x。</p> <p>根据作者介绍的 Vue 3.0 计划中，以下是计划中的公共 API 更改：</p> <ul><li>模板语法将保持 99%不变。<code>scoped-slot</code>语法可能会有一些小的调整，但是除此之外，没有计划更改模板的其他任何内容</li> <li>API 在设计时考虑了 TypeScript 的类型推断，3.x 代码库本身将使用 TypeScript 编写，并提供增强的 TypeScript 支持。也就是说，在应用程序中使用 TypeScript 仍然是完全可选的</li> <li>顶层 API 可能会进行较大的调整，以避免在安装插件时会修改 Vue 的运行时。相反，插件的作用域会局限在组件树中</li> <li>函数性的组件将支持纯函数，但是将需要通过辅助函数来显式创建异步组件</li> <li>变化最大的部分是渲染功函数（render）能中使用的虚拟 DOM 的格式</li></ul> <p>也有人会好奇，是否 Vue 3.0 出来之后，之前对 Vue 的积累和理解都需要重新学习呢？其实不是这样的，Vue 3.0 是基于原有的框架设计上，引入了一些新的理念。代码是重构了，但是思想是演进的。可以理解为我们的项目跑了两三年之后，发现除了不少好用的新技术和能力，我们就要考虑是否要进行优化或是重构了。</p> <h2 id="_16-2-设计目标"><a href="#_16-2-设计目标" class="header-anchor">#</a> 16.2 设计目标</h2> <p>总的来说，Vue 3.0 的设计目标主要有以下几点：</p> <ul><li><strong>更小</strong></li> <li><strong>更快</strong></li> <li><strong>加强 API 设计一致性</strong></li> <li><strong>加强 Typescript 支持</strong></li> <li><strong>提高自身可维护性</strong></li> <li><strong>开放更多底层功能</strong></li></ul> <p>我们一个个来看一下，Vue 3.0 的一些设计理念和实现方式调整，以及对开发者来说要怎样理解。以下内容基本上有了解 Vue 3.0 的开发者都已经从作者的分享、网上的 PPT 资源或是介绍说明中接触到，这里依然会先介绍一下。</p> <h3 id="_16-2-1-更小"><a href="#_16-2-1-更小" class="header-anchor">#</a> 16.2.1 更小</h3> <h4 id="tree-shaking"><a href="#tree-shaking" class="header-anchor">#</a> Tree-shaking</h4> <p>什么是 Tree-shaking 呢？我们在进行项目开发的时候，经常会需要引入一些开源库。但是大多数时候我们都只会使用到这个开源库中的一小部分内容，Tree-shaking 用于描述移除 JavaScript 上下文中的未引用代码。也就是说，我们在打包代码的时候，会自动移除未用到的一些特性和功能代码，以此来减少生成的代码文件大小。</p> <p>在 Vue 3.0 中，全局 API 和内置组件、功能都将支持 Tree-shaking。</p> <h4 id="_10kb-gzipped"><a href="#_10kb-gzipped" class="header-anchor">#</a> ~10kb gzipped</h4> <p>新的运行时，代码尺寸将控制在 10kb gzipped 上下。</p> <h3 id="_16-2-2-更快"><a href="#_16-2-2-更快" class="header-anchor">#</a> 16.2.2 更快</h3> <h4 id="virtual-dom"><a href="#virtual-dom" class="header-anchor">#</a> Virtual DOM</h4> <p>传统 Virtual DOM 有以下性能瓶颈：<br>
(1) 虽然 Vue 能够保证触发更新的组件最小化，但在单个组件内部依然需要遍历该组件的整个 Virtual DOM 树。<br>
(2) 在一些组件整个模版内只有少量动态节点的情况下，这些遍历都是性能的浪费。<br>
(3) 传统 Virtual DOM 的性能跟模版大小正相关，跟动态节点的数量无关。</p> <p>在 Vue 3.0 中，Virtual DOM 会完全重写，通过动静结合的模式来进行突破，更新速度和内存占用均有质的提升，整体比 Vue2 性能提升 2-5 倍。具体实现方式包括：<br>
(1) 通过模版静态分析生成更优化的 Virtual DOM 渲染函数，将模版切分为 block（<code>if</code>, <code>for</code>, <code>slot</code>)。<br>
(2) 每个 block 内部动态节点位置是固定的，同时每个 block 的根节点会记录自己所包含的动态节点（包含子 block 的根节点）。<br>
(3) 更新时只需要直接遍历动态节点，Virtual DOM 的更新性能与模版大小解耦，变为与动态节点的数量相关。</p> <p>这里可以简单理解为，Virtual DOM 的更新从以前的整体作用域调整为树状作用域，树状的结构会带来算法的简化以及性能的提升。</p> <h4 id="观察者机制"><a href="#观察者机制" class="header-anchor">#</a> 观察者机制</h4> <p>Proxy 对象是什么呢，它用于定义基本操作的自定义行为（如属性查找，赋值，枚举，函数调用等），通过<code>new Proxy(target, handler)</code>来创建，参数说明如下：</p> <p>表 16-1 <code>new Proxy()</code>参数说明</p> <table><thead><tr><th>参数</th> <th>说明</th></tr></thead> <tbody><tr><td><code>target</code></td> <td>用 Proxy 包装的目标对象（可以是任何类型的对象，包括原生数组，函数，甚至另一个代理）</td></tr> <tr><td><code>handler</code></td> <td>一个对象，其属性是当执行一个操作时定义代理的行为的函数</td></tr></tbody></table> <p>同时<code>handler</code>参数中，常用的方法包括：</p> <ul><li><code>handler.get()</code>: 用于拦截对象的读取属性操作</li> <li><code>handler.set()</code>: 用于拦截设置属性值的操作</li> <li><code>handler.getPrototypeOf()</code>: 当读取代理对象的原型时，该方法就会被调用</li> <li><code>handler.has()</code>: 针对<code>in</code>操作符的代理方法</li></ul> <p>我们能看到，当我们给某个对象添加了代理之后，就可以改变一些原有的行为，或是通过钩子的方式添加一些处理，我们用来触发界面更新、其他数据更新等也是可以的。</p> <p>相比于之前的 getter/setter 监控数据变更，Vue 3.0 将会是基于 Proxy 的变动侦测，通过代理的方式来监控变动，整体性能会得到优化。同时从长远来看，JS 引擎会持续优化 Proxy（getter/setter 基本不会变化）。</p> <h4 id="编译时优化"><a href="#编译时优化" class="header-anchor">#</a> 编译时优化</h4> <p>编译器架构重构，更多编译时（compile-time）会得到优化，以减少 runtime 开销。</p> <h3 id="_16-2-3-加强-api-设计一致性"><a href="#_16-2-3-加强-api-设计一致性" class="header-anchor">#</a> 16.2.3 加强 API 设计一致性</h3> <p>Vue 3.0 整体使用 Function-based API，对比 Class API，拥有以下优势：</p> <ul><li>更灵活的逻辑复用能力</li> <li>更好的 TypeScript 类型推导支持</li> <li>更好的性能</li> <li>Tree-shaking 友好</li> <li>代码更容易被压缩</li></ul> <h3 id="_16-2-4-加强-typescript-支持"><a href="#_16-2-4-加强-typescript-支持" class="header-anchor">#</a> 16.2.4 加强 Typescript 支持</h3> <p>Vue 3.0 本身用 TypeScript 重写，内置 typing，支持 TSX，同时不会影响不使用 TS 的用户。</p> <h3 id="_16-2-5-开放更多底层功能"><a href="#_16-2-5-开放更多底层功能" class="header-anchor">#</a> 16.2.5 开放更多底层功能</h3> <p>底层 API 会更多地开放给开发者使用，例如自定义渲染能力:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">import</span> <span class="token punctuation">{</span> createRenderer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;@vue/runtime-core&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> <span class="token punctuation">{</span> render <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">createRenderer</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  nodeOps<span class="token punctuation">,</span>
  patchData
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>以上内容，在之前的一些 Vue 分享会中也有相关说明。如今相关的源代码也已经出来了，虽然还是 Pre Alpha 阶段，但我们可以通过这部分源码来结合理解一下 Vue 3.0 是进行了怎样的进化。</p> <h2 id="_16-3-vue-3-0-pre-alpha"><a href="#_16-3-vue-3-0-pre-alpha" class="header-anchor">#</a> 16.3 Vue 3.0 Pre Alpha</h2> <p>2019 年 10 月 5 日，Vue 3.0 Pre Alpha 阶段的源代码（https://github.com/vuejs/vue-next）已经公开了。我们来看一下Vue 3.0 的设计是否都实现了，大概又是怎样实现的。</p> <h3 id="_16-3-1-代码-readme-说明"><a href="#_16-3-1-代码-readme-说明" class="header-anchor">#</a> 16.3.1 代码 README 说明</h3> <p>我们去看源代码，通常会不知道如何下手。即使是代码注释比较充分，但是数量的确是很多，要怎么从中理清楚主要的逻辑和思路呢？一般来说我们可以从 README 开始，例如我们来看看 Vue 3.0 Pre Alpha 的说明，这里主要讲了两块的内容：<strong>编译器 Compiler 和运行时 Runtime</strong>。</p> <p>其实前面宣传和分享的时候，给大家介绍的更多是目标，而源代码能更好地表达如何实现。显然，对于更快、更小、对开发者更友好等种种目标，Vue 3.0 是从编译器和运行时两大块来着手处理实现的。</p> <h4 id="编译器-compiler"><a href="#编译器-compiler" class="header-anchor">#</a> 编译器 Compiler</h4> <p>关于编译器，代码说明是包括以下调整：</p> <ul><li>模块化架构</li> <li>&quot;Block tree&quot;优化</li> <li>更激进的 static tree hoisting 功能</li> <li>Source Map 支持</li> <li>内置标识符前缀（又名“stripWith”，它会删除生成的渲染函数中的<code>with</code>用法，使它们兼容严格模式）</li> <li>内置整齐打印（pretty-print）功能</li> <li>移除 Source Map 和标识符前缀后，精简至 10kb 左右大小的 brotli 压缩的浏览器版本</li></ul> <h4 id="运行时-runtime"><a href="#运行时-runtime" class="header-anchor">#</a> 运行时 Runtime</h4> <p>关于运行时，包括以下的优化内容：</p> <ul><li>速度显著提升</li> <li>同时支持 Composition API 和 Options API，并支持 typings</li> <li>基于 Proxy 的变更检测</li> <li>支持 Fragments、Portals、Suspense w/ async setup()</li></ul> <h4 id="_2-x-功能迁移"><a href="#_2-x-功能迁移" class="header-anchor">#</a> 2.x 功能迁移</h4> <p>在该 Pre Alpha 阶段代码里，还有一些 2.x 的功能尚未完成：</p> <ul><li>服务器端渲染</li> <li><code>&lt;keep-alive&gt;</code></li> <li><code>&lt;transition&gt;</code></li> <li>编译器对 DOM 特定修饰符的转换，包括<code>v-on</code>、<code>v-model</code>、<code>v-text</code>、<code>v-pre</code>、<code>v-once</code>、<code>v-html</code>、<code>v-show</code>等，部分已完成</li></ul> <p>此外，该版本的实现还需要运行时环境中的本机 ES2015+，且尚未支持 IE11。</p> <h3 id="_16-3-2-源码欣赏"><a href="#_16-3-2-源码欣赏" class="header-anchor">#</a> 16.3.2 源码欣赏</h3> <p>我们下载了源代码之后，可以看到有以下的 packages：<br> <img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/vue-16-1.png" alt="image"></p> <p>表 16-2 Vue 3.0 Pre Alpha 源码 packages</p> <table><thead><tr><th>packages</th> <th>说明</th></tr></thead> <tbody><tr><td>compiler-core</td> <td>编译器核心，包括将模板转成 AST、生成 JS 逻辑等功能</td></tr> <tr><td>compiler-dom</td> <td>编译器 DOM 补充部分，与浏览器相关的模板编译和逻辑处理等功能</td></tr> <tr><td>reactivity</td> <td>数据相关的系统，包括数据监控（Proxy 代理）、计算和响应等基础能力</td></tr> <tr><td>runtime-core</td> <td>运行时核心，包括 Vue 组件系统、Vue 的各种 API 实现、虚拟 DOM 相关，同时暴露了更多的底层能力如自定义渲染器</td></tr> <tr><td>runtime-dom</td> <td>运行时 DOM 相关补充，包括处理原生 DOM API、DOM 事件和 DOM 属性等</td></tr> <tr><td>runtime-test</td> <td>用于测试的运行时，该运行时基于虚拟 DOM 的 JS 对象，可以用在所有 JS 环境里</td></tr> <tr><td>server-renderer</td> <td>SSR 服务端渲染</td></tr> <tr><td>shared</td> <td>包含一些通用的配置和方法</td></tr> <tr><td>template-explorer</td> <td>模板编译输出，方便调试</td></tr> <tr><td>vue</td> <td>用于构建完整版本的 Vue，使用了编译器和运行时</td></tr></tbody></table> <p>我们看到完整版本的 Vue 里引用了 compiler-dom 和 runtime-dom，但这两者其实还依赖了 compiler-core、runtime-core、reactivity，也就是最终完整的的 Vue 3.0 Pre Alpha 版本了。</p> <h4 id="vue-complier-core"><a href="#vue-complier-core" class="header-anchor">#</a> @vue/complier-core</h4> <p>翻开源码，我们其实能看到和 Vue2.x 相比一个很大的改变：整体的功能代码进行了解耦，每个功能模块都清晰独立地抽离出来了。还可以开放更多的底层能力给到开发者。</p> <p>Vue 3.0 整体使用 Function-based API，同时使用 Typescript 进行开发。除了可读性、维护性上的提升，之前提到的一些优势也都体现出来了：模块化解耦获得了更灵活的逻辑复用能力、Tree-shaking、Source Map 支持更加友好，开发者也获得更好的 TypeScript 类型推导支持。</p> <p>以 complier-core 中 index.ts 中的代码为例：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// @vue/compiler-core/src/index.ts</span>
<span class="token comment">// 函数式 API 可便捷地对逻辑进行解耦和复用</span>
<span class="token comment">// 能看到 complier-core 中功能主要包括模板解析、转成AST、生成JS逻辑等一些功能</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> parse<span class="token punctuation">,</span> ParserOptions <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./parse&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transform<span class="token punctuation">,</span> TransformOptions <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transform&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> generate<span class="token punctuation">,</span> CodegenOptions<span class="token punctuation">,</span> CodegenResult <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./codegen&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> RootNode <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./ast&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> isString <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;@vue/shared&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformIf <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vIf&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformFor <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vFor&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformExpression <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/transformExpression&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformSlotOutlet <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/transformSlotOutlet&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformElement <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/transformElement&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformOn <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vOn&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformBind <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vBind&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> defaultOnError<span class="token punctuation">,</span> createCompilerError<span class="token punctuation">,</span> ErrorCodes <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./errors&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> trackSlotScopes<span class="token punctuation">,</span> trackVForSlotScopes <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vSlot&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> optimizeText <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/optimizeText&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformOnce <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vOnce&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformModel <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vModel&quot;</span><span class="token punctuation">;</span>

<span class="token keyword">export</span> type CompilerOptions <span class="token operator">=</span> ParserOptions <span class="token operator">&amp;</span> TransformOptions <span class="token operator">&amp;</span> CodegenOptions<span class="token punctuation">;</span>

<span class="token comment">// 我们将其命名为“baseCompile”，以便更高级别的编译器（例如 @vue/compiler-dom）</span>
<span class="token comment">// 可以在重新导出其他所有内容的同时导出“compile”</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">baseCompile</span><span class="token punctuation">(</span>
  <span class="token parameter"><span class="token literal-property property">template</span><span class="token operator">:</span> string <span class="token operator">|</span> RootNode<span class="token punctuation">,</span>
  <span class="token literal-property property">options</span><span class="token operator">:</span> CompilerOptions <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="token punctuation">)</span><span class="token operator">:</span> CodegenResult <span class="token punctuation">{</span>
  <span class="token comment">// 省略一部分</span>

  <span class="token comment">// 这里先解析模板，然后生成AST对象</span>
  <span class="token keyword">const</span> ast <span class="token operator">=</span> <span class="token function">isString</span><span class="token punctuation">(</span>template<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token function">parse</span><span class="token punctuation">(</span>template<span class="token punctuation">,</span> options<span class="token punctuation">)</span> <span class="token operator">:</span> template<span class="token punctuation">;</span>

  <span class="token keyword">const</span> prefixIdentifiers <span class="token operator">=</span>
    <span class="token operator">!</span>__BROWSER__ <span class="token operator">&amp;&amp;</span>
    <span class="token punctuation">(</span>options<span class="token punctuation">.</span>prefixIdentifiers <span class="token operator">===</span> <span class="token boolean">true</span> <span class="token operator">||</span> options<span class="token punctuation">.</span>mode <span class="token operator">===</span> <span class="token string">&quot;module&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// 对每个AST对象节点进行处理</span>
  <span class="token function">transform</span><span class="token punctuation">(</span>ast<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span>options<span class="token punctuation">,</span>
    prefixIdentifiers<span class="token punctuation">,</span>
    <span class="token literal-property property">nodeTransforms</span><span class="token operator">:</span> <span class="token punctuation">[</span>
      transformIf<span class="token punctuation">,</span>
      transformFor<span class="token punctuation">,</span>
      <span class="token operator">...</span><span class="token punctuation">(</span>prefixIdentifiers
        <span class="token operator">?</span> <span class="token punctuation">[</span>
            <span class="token comment">// 此处顺序很重要</span>
            trackVForSlotScopes<span class="token punctuation">,</span>
            transformExpression
          <span class="token punctuation">]</span>
        <span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
      trackSlotScopes<span class="token punctuation">,</span>
      transformSlotOutlet<span class="token punctuation">,</span>
      transformElement<span class="token punctuation">,</span>
      optimizeText<span class="token punctuation">,</span>
      <span class="token comment">// 开放给使用者添加的一些处理逻辑</span>
      <span class="token comment">// 例如 compiler-dom 中新增了对 DOM 的一些处理</span>
      <span class="token operator">...</span><span class="token punctuation">(</span>options<span class="token punctuation">.</span>nodeTransforms <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span>
    <span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">directiveTransforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">on</span><span class="token operator">:</span> transformOn<span class="token punctuation">,</span>
      <span class="token literal-property property">bind</span><span class="token operator">:</span> transformBind<span class="token punctuation">,</span>
      <span class="token literal-property property">once</span><span class="token operator">:</span> transformOnce<span class="token punctuation">,</span>
      <span class="token literal-property property">model</span><span class="token operator">:</span> transformModel<span class="token punctuation">,</span>
      <span class="token comment">// 开放给使用者添加的一些处理逻辑</span>
      <span class="token operator">...</span><span class="token punctuation">(</span>options<span class="token punctuation">.</span>directiveTransforms <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

  <span class="token comment">// 将AST对象生成VNode、JS逻辑等</span>
  <span class="token keyword">return</span> <span class="token function">generate</span><span class="token punctuation">(</span>ast<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span>options<span class="token punctuation">,</span> <span class="token comment">// 开放给使用者添加的一些转换逻辑</span>
    prefixIdentifiers
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>从上面的代码，我们能看到，模板解析生成 AST 之后，还会根据 AST 对象来进行转换。而 Vue 3.0 中提到的 Virtual DOM 优化的内容也在这里进行，通过模版静态分析生成更优化的 Virtual DOM 渲染函数，将模版切分为 block（if, for, slot)，来提升 Virtual DOM 的性能。例如对某些语法进行“block”分块，然后整个应用以树状将每个“block”串起来，这样在更新、数据对比监控的时候，都可以从上而下地进行，也可以将变更控制在更小的范围，从而提升性能。</p> <p>其他的功能设计也跟这里比较相似，通过函数式 API 来解耦基础能力，同时留空一些可补充的能力。功能拆解后，不管是组装的灵活性，还是可测试、易拓展、Tree-shaking 等，都有质的提升。</p> <h4 id="vue-complier-dom"><a href="#vue-complier-dom" class="header-anchor">#</a> @vue/complier-dom</h4> <p>同样地，要了解这个模块主要是用来做什么，我们也需要首先打开 index.ts 文件：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// @vue/compiler-dom/src/index.ts</span>
<span class="token comment">// 依赖了@vue/compiler-core</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span>
  baseCompile<span class="token punctuation">,</span>
  CompilerOptions<span class="token punctuation">,</span>
  CodegenResult
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;@vue/compiler-core&quot;</span><span class="token punctuation">;</span>
<span class="token comment">// 与 DOM 相关的一些解析和转换</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> parserOptionsMinimal <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./parserOptionsMinimal&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> parserOptionsStandard <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./parserOptionsStandard&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformStyle <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/transformStyle&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformCloak <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vCloak&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformVHtml <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vHtml&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformVText <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vText&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> transformModel <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./transforms/vModel&quot;</span><span class="token punctuation">;</span>

<span class="token comment">// 导出补充了DOM相关的“compile”模块</span>
<span class="token keyword">export</span> <span class="token keyword">function</span> <span class="token function">compile</span><span class="token punctuation">(</span>
  <span class="token parameter"><span class="token literal-property property">template</span><span class="token operator">:</span> string<span class="token punctuation">,</span>
  <span class="token literal-property property">options</span><span class="token operator">:</span> CompilerOptions <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span></span>
<span class="token punctuation">)</span><span class="token operator">:</span> CodegenResult <span class="token punctuation">{</span>
  <span class="token comment">// 基于 @vue/compiler-core 中的 baseCompile 进行补充拓展</span>
  <span class="token comment">// 从而导出一个完整的 Vue 3.0 版本的编译器</span>
  <span class="token keyword">return</span> <span class="token function">baseCompile</span><span class="token punctuation">(</span>template<span class="token punctuation">,</span> <span class="token punctuation">{</span>
    <span class="token operator">...</span>options<span class="token punctuation">,</span>
    <span class="token operator">...</span><span class="token punctuation">(</span>__BROWSER__ <span class="token operator">?</span> parserOptionsMinimal <span class="token operator">:</span> parserOptionsStandard<span class="token punctuation">)</span><span class="token punctuation">,</span>
    <span class="token literal-property property">nodeTransforms</span><span class="token operator">:</span> <span class="token punctuation">[</span>transformStyle<span class="token punctuation">,</span> <span class="token operator">...</span><span class="token punctuation">(</span>options<span class="token punctuation">.</span>nodeTransforms <span class="token operator">||</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
    <span class="token literal-property property">directiveTransforms</span><span class="token operator">:</span> <span class="token punctuation">{</span>
      <span class="token literal-property property">cloak</span><span class="token operator">:</span> transformCloak<span class="token punctuation">,</span>
      <span class="token literal-property property">html</span><span class="token operator">:</span> transformVHtml<span class="token punctuation">,</span>
      <span class="token literal-property property">text</span><span class="token operator">:</span> transformVText<span class="token punctuation">,</span>
      <span class="token literal-property property">model</span><span class="token operator">:</span> transformModel<span class="token punctuation">,</span> <span class="token comment">// 此处重写了 compiler-core 的 vModel 转换</span>
      <span class="token operator">...</span><span class="token punctuation">(</span>options<span class="token punctuation">.</span>directiveTransforms <span class="token operator">||</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">export</span> <span class="token operator">*</span> <span class="token keyword">from</span> <span class="token string">&quot;@vue/compiler-core&quot;</span><span class="token punctuation">;</span>
</code></pre></div><p>显然，compiler-dom 模块是基于 compiler-core 模块补齐 DOM 相关能力，我们可以理解为运行在浏览器中需要的一些能力补齐。这里我们能看到，complier-dom 中重写了 compiler-core 的 vModel 转换，因为在 Vue 中<code>v-model</code>只能用在表单或是自定义表单的组件，我们来看一下实现：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// @vue/compiler-dom/src/transforms/vModel.ts</span>
<span class="token keyword">export</span> <span class="token keyword">const</span> <span class="token literal-property property">transformModel</span><span class="token operator">:</span> <span class="token function-variable function">DirectiveTransform</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">dir<span class="token punctuation">,</span> node<span class="token punctuation">,</span> context</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
  <span class="token keyword">const</span> res <span class="token operator">=</span> <span class="token function">baseTransform</span><span class="token punctuation">(</span>dir<span class="token punctuation">,</span> node<span class="token punctuation">,</span> context<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> <span class="token punctuation">{</span> tag<span class="token punctuation">,</span> tagType <span class="token punctuation">}</span> <span class="token operator">=</span> node<span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>tagType <span class="token operator">===</span> ElementTypes<span class="token punctuation">.</span><span class="token constant">ELEMENT</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 其他省略</span>

    <span class="token comment">// 显然，这里对原生的表单组件进行处理</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>tag <span class="token operator">===</span> <span class="token string">&quot;input&quot;</span> <span class="token operator">||</span> tag <span class="token operator">===</span> <span class="token string">&quot;textarea&quot;</span> <span class="token operator">||</span> tag <span class="token operator">===</span> <span class="token string">&quot;select&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">let</span> directiveToUse <span class="token operator">=</span> <span class="token constant">V_MODEL_TEXT</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span>tag <span class="token operator">===</span> <span class="token string">&quot;input&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> type <span class="token operator">=</span> <span class="token function">findProp</span><span class="token punctuation">(</span>node<span class="token punctuation">,</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">type</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>type<span class="token punctuation">)</span> <span class="token punctuation">{</span>
          <span class="token keyword">if</span> <span class="token punctuation">(</span>type<span class="token punctuation">.</span>type <span class="token operator">===</span> NodeTypes<span class="token punctuation">.</span><span class="token constant">DIRECTIVE</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// :type=&quot;foo&quot;</span>
            directiveToUse <span class="token operator">=</span> <span class="token constant">V_MODEL_DYNAMIC</span><span class="token punctuation">;</span>
          <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>type<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">switch</span> <span class="token punctuation">(</span>type<span class="token punctuation">.</span>value<span class="token punctuation">.</span>content<span class="token punctuation">)</span> <span class="token punctuation">{</span>
              <span class="token keyword">case</span> <span class="token string">&quot;radio&quot;</span><span class="token operator">:</span>
                directiveToUse <span class="token operator">=</span> <span class="token constant">V_MODEL_RADIO</span><span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
              <span class="token keyword">case</span> <span class="token string">&quot;checkbox&quot;</span><span class="token operator">:</span>
                directiveToUse <span class="token operator">=</span> <span class="token constant">V_MODEL_CHECKBOX</span><span class="token punctuation">;</span>
                <span class="token keyword">break</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
          <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>tag <span class="token operator">===</span> <span class="token string">&quot;select&quot;</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        directiveToUse <span class="token operator">=</span> <span class="token constant">V_MODEL_SELECT</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token comment">// 通过 needRuntime 返回辅助符号 // 导入将替换 resovleDirective 调用</span>
      <span class="token comment">// 注入运行时指令</span>
      res<span class="token punctuation">.</span>needRuntime <span class="token operator">=</span> context<span class="token punctuation">.</span><span class="token function">helper</span><span class="token punctuation">(</span>directiveToUse<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token comment">// 报错，此处省略</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> res<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>其实在 Vue 中，除了原生表单组件 input、textarea、select 这些，还有一些自定义组件也需要进行处理的，这里也需要补齐对自定义组件的处理，这部分我们会在 runtime-dom 运行时 DOM 补充的部分能看到。</p> <h4 id="vue-reactivity"><a href="#vue-reactivity" class="header-anchor">#</a> @vue/reactivity</h4> <p>该模块实现了一个数据管理模块，它可以单独使用，也可以与框架配合使用。我们能看到 Vue 3.0 的数据监控的优化亮点都包含在这个模块了，这个模块主要包括了：</p> <ul><li>baseHandlers/collectionHandlers: 处理器，用作 Proxy 的处理器</li> <li>computed: 计算属性部分</li> <li>effect: 一些辅助能力，例如跟踪依赖项、触发一些检测、响应等等</li> <li>reactive: 响应式数据，基于 Proxy 代理实现</li> <li>ref: 数据容器，在 Vue 中是指向组件实例的引用</li></ul> <p>我们可以看看创建响应式数据的部分：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// @vue/reactivity/src/reactive.ts</span>
<span class="token comment">// 创建响应式数据</span>
<span class="token keyword">function</span> <span class="token function">createReactiveObject</span><span class="token punctuation">(</span>
  <span class="token parameter"><span class="token literal-property property">target</span><span class="token operator">:</span> any<span class="token punctuation">,</span>
  <span class="token literal-property property">toProxy</span><span class="token operator">:</span> WeakMap<span class="token operator">&lt;</span>any<span class="token punctuation">,</span> any<span class="token operator">&gt;</span><span class="token punctuation">,</span>
  <span class="token literal-property property">toRaw</span><span class="token operator">:</span> WeakMap<span class="token operator">&lt;</span>any<span class="token punctuation">,</span> any<span class="token operator">&gt;</span><span class="token punctuation">,</span>
  <span class="token literal-property property">baseHandlers</span><span class="token operator">:</span> ProxyHandler<span class="token operator">&lt;</span>any<span class="token operator">&gt;</span><span class="token punctuation">,</span>
  <span class="token literal-property property">collectionHandlers</span><span class="token operator">:</span> ProxyHandler<span class="token operator">&lt;</span>any<span class="token operator">&gt;</span></span>
<span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">isObject</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>__DEV__<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      console<span class="token punctuation">.</span><span class="token function">warn</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">value cannot be made reactive: </span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span><span class="token function">String</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> target<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 目标已经有相应的代理</span>
  <span class="token keyword">let</span> observed <span class="token operator">=</span> toProxy<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>observed <span class="token operator">!==</span> <span class="token keyword">void</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> observed<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 目标已经是一个代理</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>toRaw<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> target<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 只有在白名单里的值可被观察</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">canObserve</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> target<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 获取集合或是非集合类型的处理器</span>
  <span class="token keyword">const</span> handlers <span class="token operator">=</span> collectionTypes<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>target<span class="token punctuation">.</span>constructor<span class="token punctuation">)</span>
    <span class="token operator">?</span> collectionHandlers
    <span class="token operator">:</span> baseHandlers<span class="token punctuation">;</span>
  <span class="token comment">// 创建代理，并记录源对象和代理对象的关系</span>
  observed <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Proxy</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> handlers<span class="token punctuation">)</span><span class="token punctuation">;</span>
  toProxy<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> observed<span class="token punctuation">)</span><span class="token punctuation">;</span>
  toRaw<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>observed<span class="token punctuation">,</span> target<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// 存储{target-&gt; key-&gt; dep}关系</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>targetMap<span class="token punctuation">.</span><span class="token function">has</span><span class="token punctuation">(</span>target<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    targetMap<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Map</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> observed<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>我们已经可以看到，通过 Proxy 的方式创建一个响应式数据，并将数据之间的依赖关系、源数据与代理对象之间的关系都记录下来，当我们更新数据的时候，就可以根据依赖进行范围内的检查更新：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// @vue/reactivity/src/baseHandlers.ts</span>
<span class="token comment">// 这是响应式数据 set 的时候代理处理函数</span>
<span class="token keyword">function</span> <span class="token function">set</span><span class="token punctuation">(</span>
  <span class="token parameter"><span class="token literal-property property">target</span><span class="token operator">:</span> any<span class="token punctuation">,</span>
  <span class="token literal-property property">key</span><span class="token operator">:</span> string <span class="token operator">|</span> symbol<span class="token punctuation">,</span>
  <span class="token literal-property property">value</span><span class="token operator">:</span> any<span class="token punctuation">,</span>
  <span class="token literal-property property">receiver</span><span class="token operator">:</span> any</span>
<span class="token punctuation">)</span><span class="token operator">:</span> boolean <span class="token punctuation">{</span>
  <span class="token comment">// 获取代理对象数据</span>
  value <span class="token operator">=</span> <span class="token function">toRaw</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// 获取原对象数据</span>
  <span class="token keyword">const</span> hadKey <span class="token operator">=</span> <span class="token function">hasOwn</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token keyword">const</span> oldValue <span class="token operator">=</span> target<span class="token punctuation">[</span>key<span class="token punctuation">]</span><span class="token punctuation">;</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token function">isRef</span><span class="token punctuation">(</span>oldValue<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span><span class="token function">isRef</span><span class="token punctuation">(</span>value<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    oldValue<span class="token punctuation">.</span>value <span class="token operator">=</span> value<span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
  <span class="token comment">// 采用 Reflect.set 方法将值赋值给对象的属性</span>
  <span class="token comment">// 确保完成原有的行为，然后再部署额外的功能</span>
  <span class="token keyword">const</span> result <span class="token operator">=</span> Reflect<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> key<span class="token punctuation">,</span> value<span class="token punctuation">,</span> receiver<span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token comment">// 如果目标是原始原型链中的某个对象，请勿触发</span>
  <span class="token comment">// 可防止循环触发</span>
  <span class="token keyword">if</span> <span class="token punctuation">(</span>target <span class="token operator">===</span> <span class="token function">toRaw</span><span class="token punctuation">(</span>receiver<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 计算数据变更方式（更新或新增），并进行变更触发</span>
    <span class="token comment">// trigger 会根据依赖关系，对 computed 和需要连带更新的数据进行更新</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>__DEV__<span class="token punctuation">)</span> <span class="token punctuation">{</span>
      <span class="token keyword">const</span> extraInfo <span class="token operator">=</span> <span class="token punctuation">{</span> oldValue<span class="token punctuation">,</span> <span class="token literal-property property">newValue</span><span class="token operator">:</span> value <span class="token punctuation">}</span><span class="token punctuation">;</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>hadKey<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">trigger</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> OperationTypes<span class="token punctuation">.</span><span class="token constant">ADD</span><span class="token punctuation">,</span> key<span class="token punctuation">,</span> extraInfo<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>value <span class="token operator">!==</span> oldValue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">trigger</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> OperationTypes<span class="token punctuation">.</span><span class="token constant">SET</span><span class="token punctuation">,</span> key<span class="token punctuation">,</span> extraInfo<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>hadKey<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">trigger</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> OperationTypes<span class="token punctuation">.</span><span class="token constant">ADD</span><span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>value <span class="token operator">!==</span> oldValue<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">trigger</span><span class="token punctuation">(</span>target<span class="token punctuation">,</span> OperationTypes<span class="token punctuation">.</span><span class="token constant">SET</span><span class="token punctuation">,</span> key<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span>
  <span class="token keyword">return</span> result<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>我们能看到，使用了 Proxy 代理+依赖关系链的方式来进行数据检测和变更更新，同时结合运行时 DOM 相关补充，就可以完成对页面的局部刷新。</p> <h4 id="vue-runtime-core"><a href="#vue-runtime-core" class="header-anchor">#</a> @vue/runtime-core</h4> <p>运行时核心模块主要包括了组件系统和 Vue 的 API 实现、虚拟 DOM 相关的功能，我们同样地可以从 index.ts 文件中看到：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// @vue/runtime-core/src/index.ts</span>
<span class="token comment">// 公共API部分------------</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> createComponent <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./apiCreateComponent&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> nextTick <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./scheduler&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token operator">*</span> <span class="token keyword">from</span> <span class="token string">&quot;./apiReactivity&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token operator">*</span> <span class="token keyword">from</span> <span class="token string">&quot;./apiWatch&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token operator">*</span> <span class="token keyword">from</span> <span class="token string">&quot;./apiLifecycle&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token operator">*</span> <span class="token keyword">from</span> <span class="token string">&quot;./apiInject&quot;</span><span class="token punctuation">;</span>

<span class="token comment">// 高级API部分--------------</span>
<span class="token comment">// 需要进行原始渲染功能的用户可以使用</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> h <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./h&quot;</span><span class="token punctuation">;</span>
<span class="token comment">// VNode（虚拟DOM）相关能力</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span>
  createVNode<span class="token punctuation">,</span>
  cloneVNode<span class="token punctuation">,</span>
  mergeProps<span class="token punctuation">,</span>
  openBlock<span class="token punctuation">,</span>
  createBlock
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./vnode&quot;</span><span class="token punctuation">;</span>
<span class="token comment">// VNode类型的symbols</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> Text<span class="token punctuation">,</span> Comment<span class="token punctuation">,</span> Fragment<span class="token punctuation">,</span> Portal<span class="token punctuation">,</span> Suspense <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./vnode&quot;</span><span class="token punctuation">;</span>
<span class="token comment">// VNode的标志</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> PublicShapeFlags <span class="token keyword">as</span> ShapeFlags <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./shapeFlags&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> PublicPatchFlags <span class="token keyword">as</span> PatchFlags <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;@vue/shared&quot;</span><span class="token punctuation">;</span>

<span class="token comment">// 可用于高级插件</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> getCurrentInstance <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./component&quot;</span><span class="token punctuation">;</span>

<span class="token comment">// 可用于自定义渲染</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> createRenderer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./createRenderer&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> warn <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./warning&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span>
  handleError<span class="token punctuation">,</span>
  callWithErrorHandling<span class="token punctuation">,</span>
  callWithAsyncErrorHandling
<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./errorHandling&quot;</span><span class="token punctuation">;</span>

<span class="token comment">// 内部API，用于编译器生成的代码</span>
<span class="token comment">// 应该与'@vue/compiler-core/src/runtimeConstants.ts'同步</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> applyDirectives <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./directives&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> resolveComponent<span class="token punctuation">,</span> resolveDirective <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./helpers/resolveAssets&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> renderList <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./helpers/renderList&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> toString <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./helpers/toString&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> toHandlers <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./helpers/toHandlers&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> renderSlot <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./helpers/renderSlot&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> createSlots <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./helpers/createSlots&quot;</span><span class="token punctuation">;</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> capitalize<span class="token punctuation">,</span> camelize <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;@vue/shared&quot;</span><span class="token punctuation">;</span>

<span class="token comment">// 内部API，用于与运行时编译器集成</span>
<span class="token keyword">export</span> <span class="token punctuation">{</span> registerRuntimeCompiler <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">&quot;./component&quot;</span><span class="token punctuation">;</span>
</code></pre></div><p>我们能看到，runtime-core 暴露了一些底层 API 能力，例如自定义渲染等，开发者可以基于这些基础能力之上，补充平台相关能力，打造一个完整的运行时。像@vue/runtime-dom 就时补充了 DOM 相关的运行时能力，从而构成完整的 Vue 运行时功能模块。</p> <h4 id="vue-runtime-dom"><a href="#vue-runtime-dom" class="header-anchor">#</a> @vue/runtime-dom</h4> <p>runtime-dom 模块是基于 runtime-core 开发的浏览器上的运行时，主要补齐了浏览器环境下 DOM 节点和节点属性的一些渲染和更新能力。</p> <p>怎么补齐呢？我们看一个例子：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// @vue/runtime-dom/src/nodeOps.ts</span>
<span class="token comment">// 对一些 VNode 操作，增加更新到页面的 DOM 节点操作</span>

<span class="token comment">// 获取 document 对象</span>
<span class="token keyword">const</span> doc <span class="token operator">=</span> document<span class="token punctuation">;</span>

<span class="token keyword">export</span> <span class="token keyword">const</span> nodeOps <span class="token operator">=</span> <span class="token punctuation">{</span>
  <span class="token function-variable function">insert</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">child</span><span class="token operator">:</span> Node<span class="token punctuation">,</span> <span class="token literal-property property">parent</span><span class="token operator">:</span> Node<span class="token punctuation">,</span> anchor<span class="token operator">?</span><span class="token operator">:</span> Node</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>anchor <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      parent<span class="token punctuation">.</span><span class="token function">insertBefore</span><span class="token punctuation">(</span>child<span class="token punctuation">,</span> anchor<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
      parent<span class="token punctuation">.</span><span class="token function">appendChild</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  <span class="token function-variable function">remove</span><span class="token operator">:</span> <span class="token punctuation">(</span><span class="token parameter"><span class="token literal-property property">child</span><span class="token operator">:</span> Node</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> parent <span class="token operator">=</span> child<span class="token punctuation">.</span>parentNode<span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>parent <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
      parent<span class="token punctuation">.</span><span class="token function">removeChild</span><span class="token punctuation">(</span>child<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
  <span class="token punctuation">}</span><span class="token punctuation">,</span>

  <span class="token literal-property property">createElement</span><span class="token operator">:</span> <span class="token punctuation">(</span>tag<span class="token operator">:</span> string<span class="token punctuation">,</span> isSVG<span class="token operator">?</span><span class="token operator">:</span> boolean<span class="token punctuation">)</span><span class="token operator">:</span> <span class="token parameter">Element</span> <span class="token operator">=&gt;</span>
    isSVG <span class="token operator">?</span> doc<span class="token punctuation">.</span><span class="token function">createElementNS</span><span class="token punctuation">(</span>svgNS<span class="token punctuation">,</span> tag<span class="token punctuation">)</span> <span class="token operator">:</span> doc<span class="token punctuation">.</span><span class="token function">createElement</span><span class="token punctuation">(</span>tag<span class="token punctuation">)</span><span class="token punctuation">,</span>

  <span class="token literal-property property">querySelector</span><span class="token operator">:</span> <span class="token punctuation">(</span>selector<span class="token operator">:</span> string<span class="token punctuation">)</span><span class="token operator">:</span> Element <span class="token operator">|</span> <span class="token parameter"><span class="token keyword">null</span></span> <span class="token operator">=&gt;</span>
    doc<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span>selector<span class="token punctuation">)</span>

  <span class="token comment">// 篇幅原因，省略一部分内容</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
</code></pre></div><p>我们可以通过<code>runtime-core</code>提供的自定义渲染能力，把 DOM 节点增删改查的能力添加进去：</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token comment">// @vue/runtime-dom/src/index.ts</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> createRenderer <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'@vue/runtime-core'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> nodeOps <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./nodeOps'</span>
<span class="token keyword">import</span> <span class="token punctuation">{</span> patchProp <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'./patchProp'</span>

<span class="token keyword">const</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> createApp <span class="token punctuation">}</span> <span class="token operator">=</span> createRenderer<span class="token operator">&lt;</span>Node<span class="token punctuation">,</span> Element<span class="token operator">&gt;</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
  patchProp<span class="token punctuation">,</span>
  <span class="token operator">...</span>nodeOps
<span class="token punctuation">}</span><span class="token punctuation">)</span>

<span class="token keyword">export</span> <span class="token punctuation">{</span> render<span class="token punctuation">,</span> createApp <span class="token punctuation">}</span>
</code></pre></div><p>所以在 Vue 3.0 版本中，可以通过 render 和 createApp 这两个 API 来进行初始化项目和页面渲染。</p> <h4 id="其他模块"><a href="#其他模块" class="header-anchor">#</a> 其他模块</h4> <p>对于其他模块（runtime-test、server-renderer、shared、template-explorer、vue），前面也有简单介绍，篇幅关系就不再一个个描述了。</p> <p>回顾一下 Vue 3.0 的目标（更小、更快、加强 API 设计一致性、加强 Typescript 支持、提高自身可维护性、开放更多底层功能），其实基本上都达成了。</p> <p>重构是一件很花精力、考验团队能力的事情，尤其是在 Vue 本身就很受欢迎的情况下，依然决定要进行重构。虽然偶尔会有些“学不动”的捣乱声音，但作为技术人，该有的追求还是要有的，如今互联网世界日新月异，止步不前只会面临被淘汰。而 Vue 3.0 的这一番举动，个人觉得真的是很棒的一个决定。</p></div> <!----> <footer class="page-edit"><div class="edit-link"><a href="https://github.com/godbasin/vue-ebook/edit/ebook-sourcecode/docs/vue-ebook/16.md" target="_blank" rel="noopener noreferrer">帮阿猪改善此页面！</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div> <!----> <div style="margin-top:30px;"><div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-sm-0 el-col-md-2 el-col-lg-4" style="padding-left:10px;padding-right:10px;display:block;"><div style="width:1px;height:1px;"></div></div> <div class="el-col el-col-24 el-col-sm-24 el-col-md-18 el-col-lg-16" style="padding-left:10px;padding-right:10px;"><div class="el-card box-card is-always-shadow"><div class="el-card__header"><div class="clearfix"><span>温馨提示喵</span></div></div><div class="el-card__body"> <div class="el-row" style="margin-left:-10px;margin-right:-10px;"><div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="el-image"><div class="image-slot"><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/loading.gif" style="width:100%;"></div><!----></div></div> <div class="el-col el-col-24 el-col-xs-24 el-col-sm-12" style="padding-left:10px;padding-right:10px;"><div class="copyright-text"><div>本书采用“保持署名—非商用”<a href="http://creativecommons.org/licenses/by-nc/4.0/" target="_blank">创意共享4.0许可证</a>。只要保持原作者署名和非商用，您可以自由地阅读、分享、修改本书。</div> <div>作者：<a href="https://github.com/godbasin" target="_blank">被删</a></div></div></div></div></div></div></div></div></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/vue-ebook/vue-ebook/15.html" class="prev">
          第15章 Vue 周边拓展
        </a></span> <span class="next"><a href="/vue-ebook/vue-ebook/99.html">
          关于框架选型
        </a>
        →
      </span></p></div>  <div class="gitalk-container theme-default-content"><div id="gitalk-container" class="content"></div></div></main> <div id="kitty-container"><span><div role="tooltip" id="el-popover-8845" aria-hidden="true" class="el-popover el-popper" style="width:undefinedpx;display:none;"><!----><img src="https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/2code2.jpg" class="image"> <div class="text">牡羊猪的猫粮罐</div> </div><span class="el-popover__reference-wrapper"><div id="kitty" style="background:url(https://github-imglib-1255459943.cos.ap-chengdu.myqcloud.com/assets/img/kitty2.svg);"></div></span></span> <div class="el-dialog__wrapper" style="display:none;"><div role="dialog" aria-modal="true" aria-label="牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）" class="el-dialog" style="margin-top:15vh;"><div class="el-dialog__header"><span class="el-dialog__title">牡羊猪是这样渐渐胖成猪的喵（点击图片可以切换噢）</span><button type="button" aria-label="Close" class="el-dialog__headerbtn"><i class="el-dialog__close el-icon el-icon-close"></i></button></div><!----><!----></div></div></div></div><div class="global-ui"></div></div>
    <script src="/vue-ebook/assets/js/app.a856ee15.js" defer></script><script src="/vue-ebook/assets/js/2.2a4d101b.js" defer></script><script src="/vue-ebook/assets/js/3.9083e877.js" defer></script><script src="/vue-ebook/assets/js/15.e8ce977a.js" defer></script>
  </body>
</html>
